<template>
  <div>
    <!--    <div>-->
    <!--      <button @click="insertText">insert text</button>-->
    <!--      <button @click="printHtml">print html</button>-->
    <!--      <button @click="disable">disable</button>-->
    <!--    </div>-->
    <div style="border: 1px solid #ccc; margin-top: 10px">
      <Toolbar
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        mode="default"
        style="border-bottom: 1px solid #ccc"
      />
      <Editor
        :defaultConfig="editorConfig"
        mode="default"
        v-model="valueHtml"
        style="height: 400px; overflow-y: hidden"
        @onCreated="handleCreated"
        @onChange="handleChange"
        @onDestroyed="handleDestroyed"
        @onFocus="handleFocus"
        @onBlur="handleBlur"
        @customAlert="customAlert"
        @customPaste="customPaste"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import systemApi from '@/service/api/system'
import type { IToolbarConfig } from '@wangeditor/editor'
type PropsState = {
  modelValue: string
}
const props = withDefaults(defineProps<PropsState>(), {
  modelValue: ''
})
const emit = defineEmits(['update:modelValue'])

type InsertFnType = (url: string, poster: string) => void
const editorRef = shallowRef()
const valueHtml = ref('')
watch(
  () => props.modelValue,
  newVal => {
    if (newVal !== valueHtml.value) {
      valueHtml.value = newVal
    }
  },
  {
    immediate: true
  }
)
const toolbarConfig: Partial<IToolbarConfig> = {
  toolbarKeys: [
    'blockquote',
    'header1',
    'header2',
    'header3',
    '|',
    'bold',
    'underline',
    'italic',
    'through',
    'color',
    'bgColor',
    'clearStyle',
    '|',
    'bulletedList',
    'numberedList',
    'todo',
    'justifyLeft',
    'justifyRight',
    'justifyCenter',
    '|',
    'insertLink',
    {
      key: 'group-image',
      title: '图片',
      iconSvg:
        '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
      menuKeys: ['insertImage', 'uploadImage']
    },
    {
      key: 'group-video',
      title: '视频',
      iconSvg:
        '<svg viewBox="0 0 1024 1024"><path d="M981.184 160.096C837.568 139.456 678.848 128 512 128S186.432 139.456 42.816 160.096C15.296 267.808 0 386.848 0 512s15.264 244.16 42.816 351.904C186.464 884.544 345.152 896 512 896s325.568-11.456 469.184-32.096C1008.704 756.192 1024 637.152 1024 512s-15.264-244.16-42.816-351.904zM384 704V320l320 192-320 192z"></path></svg>',
      menuKeys: ['insertVideo', 'uploadVideo']
    },
    'insertTable',
    'codeBlock',
    '|',
    'undo',
    'redo',
    '|',
    'fullScreen'
  ]
}
const editorConfig = {
  valueHtml: props.modelValue,
  placeholder: '请输入内容...',
  MENU_CONF: {
    uploadImage: {
      // 自定义上传
      async customUpload(file: File, insertFn: InsertFnType) {
        const params: any = new FormData()
        params.append('file', file)
        systemApi.upload(params).then(({ data }) => {
          insertFn(data.url, '')
        })
      },
      // form-data fieldName ，默认值 'wangeditor-uploaded-image'
      fieldName: 'your-custom-name',

      // 单个文件的最大体积限制，默认为 2M
      maxFileSize: 1 * 1024 * 1024, // 1M

      // 最多可上传几个文件，默认为 100
      maxNumberOfFiles: 10,

      // 选择文件时的类型限制，默认为 ['image/*'] 。如不想限制，则设置为 []
      allowedFileTypes: ['image/*'],

      // 自定义上传参数，例如传递验证的 token 等。参数会被添加到 formData 中，一起上传到服务端。
      meta: {
        token: 'xxx',
        otherKey: 'yyy'
      },

      // 将 meta 拼接到 url 参数中，默认 false
      metaWithUrl: false,

      // 自定义增加 http  header
      headers: {
        Accept: 'text/x-json',
        otherKey: 'xxx'
      },

      // 跨域是否传递 cookie ，默认为 false
      withCredentials: true,

      // 超时时间，默认为 10 秒
      timeout: 5 * 1000 // 5 秒
    },
    uploadVideo: {
      // 自定义上传
      async customUpload(file: File, insertFn: InsertFnType) {
        const params: any = new FormData()
        params.append('file', file)
        systemApi.upload(params).then(({ data }) => {
          insertFn(data.url, '')
        })
      },
      fieldName: 'your-custom-name',
      server: '/api/upload',
      // 单个文件的最大体积限制，默认为 10M
      maxFileSize: 50 * 1024 * 1024, // 5M
      // 最多可上传几个文件，默认为 5
      maxNumberOfFiles: 3,
      // 选择文件时的类型限制，默认为 ['video/*'] 。如不想限制，则设置为 []
      allowedFileTypes: ['video/*'],
      // 自定义上传参数，例如传递验证的 token 等。参数会被添加到 formData 中，一起上传到服务端。
      meta: {
        token: 'xxx',
        otherKey: 'yyy'
      },
      // 将 meta 拼接到 url 参数中，默认 false
      metaWithUrl: false,
      // 自定义增加 http  header
      headers: {
        Accept: 'text/x-json',
        otherKey: 'xxx'
      },
      // 跨域是否传递 cookie ，默认为 false
      withCredentials: true,

      // 超时时间，默认为 30 秒
      timeout: 15 * 1000 // 15 秒
    }
  }
}

// 组件销毁时，也及时销毁编辑器，重要！
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return

  editor.destroy()
})

// 编辑器回调函数
const handleCreated = editor => {
  console.log('created', editor)
  editorRef.value = editor // 记录 editor 实例，重要！
}
const handleChange = editor => {
  emit('update:modelValue', editor.getHtml())
}
const handleDestroyed = editor => {
  console.log('destroyed', editor)
}
const handleFocus = editor => {
  console.log('focus', editor)
}
const handleBlur = editor => {
  console.log('blur', editor)
}
const customAlert = (info, type) => {
  alert(`【自定义提示】${type} - ${info}`)
}
const customPaste = (editor, event, callback) => {
  console.log('ClipboardEvent 粘贴事件对象', event)

  // 自定义插入内容
  // editor.insertText('xxx')

  // 返回值（注意，vue 事件的返回值，不能用 return）
  callback(true) // 返回 false ，阻止默认粘贴行为
  // callback(true) // 返回 true ，继续默认的粘贴行为
}

const insertText = () => {
  const editor = editorRef.value
  if (editor == null) return
  editor.insertText('hello world')
}

const printHtml = () => {
  const editor = editorRef.value
  if (editor == null) return
  console.log(editor.getHtml())
}

const disable = () => {
  const editor = editorRef.value
  if (editor == null) return
  editor.disable()
}

const getImages = () => {
  const editor = editorRef.value
  return editor.getElemsByType('image')
}
defineExpose({
  getImages
})
</script>
